/*
 * pixiv_down - CLI-based downloading tool for https://www.pixiv.net.
 * Copyright (C) 2024, 2025  Mio
 *
 * This program is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, version 3 of the License.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program.  If not, see <https://www.gnu.org/licenses/>.
 */
module app.cmds.novel;

import std.experimental.logger;
import std.stdio;

import pd.configuration;
import pd.pixiv;
import app.util;

int novelHandle(string[] args, const ref Config config)
{
   import std.algorithm.searching : all, countUntil;
   import std.algorithm.mutation : remove;
   import std.ascii : isDigit;
   import std.getopt : getopt, GetOptOption = config;
   import pd.error_cache;

   // id => error_message
   string[string] errors;
   bool groupErrors;
   ErrorCache errorCache = loadErrorCache();
   scope (exit) save(errorCache);

   // novel <id...>
   if (args.length < 2) {
      displayNovelHelp();
      return 1;
   }

   auto helpInformation = getopt(args,
      GetOptOption.passThrough,
      "group-errors", &groupErrors);

   if (helpInformation.helpWanted) {
      displayNovelHelp();
      return 0;
   }

   infof("grouping errors = %s", groupErrors);

   foreach(arg; args[2..$]) {
      if (false == all!isDigit(arg)) {
         errorf("invalid ID: %s", arg);
         if (groupErrors) {
            errors[arg] = "Invalid ID. Must be all numbers.";
            continue;
         } else {
            stderr.writefln("Error: Invalid ID: %s", arg);
            continue;
         }
      }
      try {
         fetchAndDownloadNovel(arg, config);
	 errorCache.novels.removeKey(arg);
     } catch (Exception e) {
         errorCache.novels.insert(arg);
         errors[arg] = e.msg;
      }
   }

   return 0;
}

public void displayNovelHelp()
{
   stderr.writefln(
      "pixiv_down novel - Download specific novel(s)\n" ~
      "\nUsage:\tpixiv_down novel [options] <id> [<additional ids...>]\n" ~
      "\nYou can download one or more novels via this command.  Any\n" ~
      "novels that fail to download are mentioned after attempting to\n" ~
      "download, you can change this to only print at the end by using the\n" ~
      "--group-errors option.\n" ~
      "\nOptions:\n" ~
      "   --group-errors\tDisplay errors at the end instead.\n" ~
      "\nExamples:\n" ~
      "\n  Download a single novel:\n" ~
      "       pixiv_down artwork id\n" ~
      "\n  Download multiple novels and display failed IDs at the end:\n" ~
      "       pixiv_down artwork --group-errors id1 id2\n");
}

private:

void fetchAndDownloadNovel(string id, const ref Config config)
{
   import pd.pixiv_downloader : downloadNovel;

   tracef("fetching information for %s", id);
   const novel = fetchNovelInfo(id, config);
   downloadNovel(novel, config);
}
